//
//  XMOpenAIChatLLM.swift
//  XMLangChain
//
//  Created by xm on 2025/11/5.
//

import Foundation

protocol OpenAITool: Codable {}

public struct XMOpenAIChatMessage: XMChatMessage {
    
    public var role: XMSuperChatRole
    
    public var content: String?
    
}

/// Chat Completions 响应体，解析文本回复或工具调用
public struct XMOpenAIChatResponse: XMChatResponseMessage {
    
    public struct Message: Decodable {
        
        public struct MessageContent: Decodable {
            let role: String
            /// 文本回复可能为空，当触发工具调用时由 toolCalls 提供
            let content: String?
            /// 函数/工具调用信息
            let toolCalls: [ToolCall]?
            
            enum CodingKeys: String, CodingKey {
                case role
                case content
                case toolCalls = "tool_calls"
            }
            
            /// 工具调用信息，包含函数名与参数
            struct ToolCall: Decodable {
                struct Function: Decodable {
                    let name: String       // 被调用的函数名
                    let arguments: String  // 函数 JSON 参数
                }
                let id: String
                let type: String
                let function: Function
            }
        }
        
        let message: MessageContent
    }
    
    /// 模型可能生成多个候选回复，这里只解析必要字段
    let choices: [Message]
}



private struct OpenAIPayload: Encodable {
    let messages: [XMOpenAIChatMessage]     // 会话上下文
    let model: String               // 调用的模型名称
    let temperature: Double         // 温度参数
    let tools: [OpenAIAppTool]            // 可选工具列表，供模型选择
    
    public init(messages: [XMOpenAIChatMessage], model: String, temperature: Double, tools: [OpenAIAppTool]) {
        self.messages = messages
        self.model = model
        self.temperature = temperature
        self.tools = tools
    }
}



public struct OpenAIAppTool: XMAppTool {
    
    let type: String = "function" // 目前是固定的值，不可修改
    
    var function: OpenAIAppFunctionSpec
    
    public init(function: OpenAIAppFunctionSpec) {
        self.function = function
    }
}


public struct OpenAIAppFunctionSpec: Encodable {
    
    let name: String // 函数名称
    
    let description: String // 函数的功能描述
    
    let parameters: OpenAIAppFunctionParameters // 函数所需的参数
    
    public init(name: String, description: String, parameters: OpenAIAppFunctionParameters) {
        self.name = name
        self.description = description
        self.parameters = parameters
    }
}

public struct OpenAIAppFunctionParameters: Encodable {
    
    var type: String = "object"
    
    var properties: [String: OpenAIAppFunctionParametersProperty] = [:]
    
    var required: [String] = []
    
    public init(type: String, properties: [String : OpenAIAppFunctionParametersProperty], required: [String]) {
        self.type = type
        self.properties = properties
        self.required = required
    }
    
}

public struct OpenAIAppFunctionParametersProperty: Encodable {
    
    let type: String // 参数类型
    
    let description: String // 参数功能描述
    
    public init(type: String, description: String) {
        self.type = type
        self.description = description
    }
}


/// LangChain 初始化所需的配置参数
public struct OpenAIConfig {
    /// OpenAI 或兼容服务的 API Key
    public let apiKey: String
    /// 服务地址，默认使用 OpenAI 官方地址
    public let baseURL: URL
    /// 模型名称，例如 `gpt-4o-mini`
    public let model: String
    /// 温度参数，控制回复的发散程度
    public let temperature: Double
    
    public init(
        apiKey: String,
        baseURL: URL = URL(string: "https://api.openai.com/v1/chat/completions")!,
        model: String = "gpt-4o-mini",
        temperature: Double = 0.7
    ) {
        self.apiKey = apiKey
        self.baseURL = baseURL
        self.model = model
        self.temperature = temperature
    }
}

/// OpenAI Chat Completions
public final class XMOpenAIChatLLM: XMLLMProvider {
    private let config: OpenAIConfig
    public var session: URLSession
    
    public init(config: OpenAIConfig, session: URLSession = .shared) {
        self.config = config
        self.session = session
    }
    
    public func send(messages: [XMOpenAIChatMessage], tools: [OpenAIAppTool]) async throws -> XMOpenAIChatResponse {
        
        let payload = OpenAIPayload(
            messages: messages,
            model: config.model,
            temperature: config.temperature,
            tools: tools
        )
        
        return try await send_(url: config.baseURL,
              method: "POST",
              headers: [
                "Content-Type": "application/json",
                "Authorization": "Bearer \(config.apiKey)"
              ], body: payload)
        
    }
}



